'''

    DataK - A database system with tree data and revision control.

    DataK uses the file system to store items so that everything is easily
    accessible from any system/application.
    The items are organized in a tree structure (folders) and references (links).
    Attributes of the Items are stored in text files.
    Versioning of every Item, reference and attribute is optionally done
    transparently by subversion.

    In a very pythonic style, no attribute is typed, it's up to you to feed them
    with whatever you want.

    DataK is the crossing of xml (tree structure), sql (queries, access concurrency, rollback),
    excel (formulas) with the ease of text files and granular versioning.

    You need pysvn to use DataK versioning:
        sudo apt-get install python-svn

    DataK have three really simplistic concepts:
        Item, Attribute and Value.

        ** ITEMS **
        An item has an id, a name and a value.
        It has a parent item and can have children.
        It can have a list of attributes.
        On disk, items are folders which path is the id.
        Some items may refer to other items (referenced children), in this
        case they are stored in symbolic links.

        ** ATTRIBUTES **
        Attributes belong to one item and have a value.
        On disk, attributes are files named like the attribute, containing
        the attribute value in ascii and stored in the owner item's folder
        The attribute '_type' is a special one used to override the default type
        of the item (which is 'Item')

        ** VALUE **
        - Item's value defaults to its name and can be overridden by the content of
        a file named _value in the item's folder (="_value" attribute).
        - Attribute's value defaults to its name and can be overridden by the
        content of the attribute's file.
        - An overridden value is always stored as python code. This code is
        executed when the value is fetched. The un-executed string is called
        the formula.
        - The value of an un-existing attribute is get from the attribute of the parent.
          Except for the type
        - Requesting access to an un-existing items is an error.

    Data structure example:
    <server>/
        DATABASE1/
            TABLE1/
                Ok/
                    attr1=0
                    _value="self.attr1"
                Cancel/
                    attr1=1
                    _value="self.attr1"
            TABLE2/
                ROW1/
                    attr1=128
                    attr2="this is VARCHAR"
                    attr3=link->DATABASE.TABLE1.ROW2
                ROW2/
                    attr1=64
                    attr2=[1,2,3]

'''

from _core import *


def __InitTestServer(cnt):
    libItemPaths = {}
    config = cnt.Insert( "Config" )
    statuses = config.Insert( "Status" )
    for value, name in enumerate( ("_", "INV", "WIP", "CHK", "RTK", "FNL") ):
        status = statuses.Insert( name )
        status.value = value
    lib = cnt.Insert( "LIB" )
    for type in ("CHARS","SETS","PROPS"):
        libType = lib.Insert(type)
        for i in range(5):
            fam = libType.Insert('FAMILY'+str(i).zfill(2))
            libItemPaths[type] = []
            for j in range(3):
                libItem = fam.Insert( type.title()+str(i).zfill(2)+str(j).zfill(2))
                libItemPaths[type].append( libItem.id )
    for i,  epName in enumerate(('ep001', 'ep002', 'ep003', )):
        ep = cnt.Insert( epName )
        ep.order = i
        ep.act = "Act"+str(i).zfill(3)
        seqNames = ('S0100', 'S0200', 'S0300', )
        disabled = False
        for i, seqName in enumerate(seqNames):
            seq = ep.Insert( seqName )
            seq.order = len(seqNames)-i
            seq.disabled = disabled
            disabled = not disabled
            start = 1
            for shotNum in range(10):
                shot = seq.Insert( 'P'+str(shotNum).zfill(3) )
                shot.order = shotNum
                edit = shot.Insert( 'EDIT' )
                edit.value = "str(self.start)+'->'+str(self.end)"
                edit.start = start
                edit.end = start+24
                start = edit.end+1
                casting = shot.Insert('CASTING')
                for type in ("CHARS","SETS","PROPS"):
                    typedCasting = casting.Insert(type)
                    typedCasting.value = "[i.value for i in self]"
                    for i in range( len(libItemPaths[type])-shotNum ):
                        typedCasting.Insert( None,  libItemPaths[type][i] )
                shot.HasHair = shotNum % 2 == 0
                shot.HasCFX = shotNum % 3 == 0
                shot.HasSFX = shotNum % 4 == 0
                

def __Test():
    server = '/tmp/dtkTest'
    try:
        cnt = Connection( server )
    except ConnectionError:
        print "Building Test Server in",  server
        CreateDataK( server )
        cnt = Connection( server )
    roots = [ i for i in cnt ]
    if not roots:
        __InitTestServer(cnt)

    seq=Item(cnt, 'ep001/S0100')
    print "ep001 act:",  cnt.Get('./ep001.act')
    print "Seq act (herited attribute):",  seq.Get('.act~')
#    PrintTree( seq, ('order', 'disabled','HasHair', 'HasCFX', 'HasSFX' ) )

    cnt.SortBy( ('order', ) )
#    print seq.order,  seq._GetAttr('order'),  seq.Get('.order'),  seq.Exec('.order')
#    print cnt.Get('./ep*/S*.order'),  cnt.Exec('./ep*/S*.order',  () )

    print 'ep001.order:',  cnt.Exec( './ep001.order' )
    print 'ep order for seq:',  seq.GetParent().order
    print 'ep order for seq:',  seq.Exec( '../.order' )

#    print cnt.Exec(  'list( reversed( ./ep*/S*.order ) )' )
    print "Episodes 2 Shots:\n",  '\n'.join( [str(i) for i in cnt.Get("./ep002/*/*")] )
#    print cnt.Exec( "./ep001/S0100.order < 2 and not ./ep001/S0100.disabled" )

#    cnt.Select(
#        {
#            'ep*/S*/P*/EDIT' : ('start','end'),
#            'ep*/S*'             : ('.order',),
#        },
#        where={
#            'ep*/S*/P*/EDIT' : '../.HasHair and not ../.disabled',
#            'ep*/S*'             : '.act == 3'
#        }
#    )

    import pprint
    pprint.pprint( cnt.Select('ep*/S*.disabled', '.disabled') )
    pprint.pprint( cnt.Select( './ep*/S*/P*',  './EDIT.start % 2' ) )
    pprint.pprint(
        cnt.Select(
            { './ep*/S*/P*': ('HasHair', 'act~') }, 
            { './ep*/S*/P*': 'not .disabled~' }
        )
    )
    
    
if __name__ == "__main__":
    __Test()






